package com.kanan.vueupload.utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;


import com.kanan.vueupload.config.RedisUtils;
import com.kanan.vueupload.constatnt.Constant;
import com.kanan.vueupload.entity.MultipartFileParamEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author kanan
 * @version 1.0
 * @return 文件上传工具类
 * @since 2021-1-17
 */
@Component
public class MultipartFileUploadUtils {


    @Autowired
    private RedisUtils redisUtils;

    @Value("${web.upload.read.max-size}")
    private int maxSize;

    /**
     * 校验文件切片上传参数(字节流文件不能为空)
     *
     * @param fileinfo:上传参数实体类
     * @return 判断是否文件切片上传，true：切片上传，false:单文件整体上传
     * @throws Exception
     */
    public Boolean checkMultipartFileParams(MultipartFileParamEntity fileinfo) {
        if (fileinfo != null) {
            if (fileinfo.getTotalChunks() != null && fileinfo.getChunkNumber() != null && fileinfo.getTotalChunks() > 1
                    && fileinfo.getChunkNumber() >= 0 && fileinfo.getTotalChunks() > fileinfo.getChunkNumber()) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 校验文件单文件上传参数(字节流文件不能为空)
     *
     * @param fileinfo:上传参数实体类
     * @return 判断参数上传是否合法，true：符合单文件上传参数格式，false:不符合单文件格式
     * @throws Exception
     */
    public Boolean checkSingleFileParams(MultipartFileParamEntity fileinfo) {
        if (fileinfo != null) {
            if (fileinfo.getTotalChunks() == null && fileinfo.getChunkNumber() == null) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 保存文件到指定目录
     * @throws Exception 异常
     */
    public void saveFile2DirPath(MultipartFile file, File targetFile) throws Exception {
        if (targetFile.createNewFile()) {
            file.transferTo(targetFile);
        }
    }

    /**
     * 创建空目标文件
     * @throws IOException IO异常
     */
    public void readySpaceFile(MultipartFileParamEntity fileinfo, File tempFile) throws IOException {
        RandomAccessFile targetSpaceFile = new RandomAccessFile(tempFile, "rws");
        targetSpaceFile.setLength(fileinfo.getTotalSize());
        System.out.println("创建文件：" + fileinfo.getTotalSize());
        targetSpaceFile.close();
    }

    /**
     * 向空文件写入二进制数据
     * @param file:数据源文件
     * @throws Exception 异常
     */
    @SuppressWarnings("resource")
    public void spaceFileWriter(MultipartFile file, File tempFile, MultipartFileParamEntity fileInfo) throws Exception {
        RandomAccessFile raf = new RandomAccessFile(tempFile, "rw");
        BufferedInputStream sourceBuffer = new BufferedInputStream(file.getInputStream());
        //获取文件写入的起始位置点
        Long startPointer = getFileWriterStartPointer(file, fileInfo);
        //初始化文件指针起始位置
        raf.seek(startPointer);
        byte[] bt = new byte[maxSize];

        try {
            while (sourceBuffer.read(bt) != -1) {
                raf.write(bt);
            }
            String identifier = fileInfo.getIdentifier();
            //文件写入完成 redis记录分片信息 用来做断电续传以及md5秒传
            //记录分片
            redisUtils.setForSet(Constant.CHUNK_KEY+identifier,fileInfo.getChunkNumber());
        }finally {
            //关闭流
            sourceBuffer.close();
            raf.close();
        }
    }

    /**
     * 计算指针开始位置
     *
     * @param fileInfo:分片实体类
     * @param file:文件流
     * @throws Exception 异常
     */
    synchronized public static Long getFileWriterStartPointer(MultipartFile file, MultipartFileParamEntity fileInfo) throws Exception {
        // TODO Auto-generated method stub
        long chunkSize = file.getSize();
        Long currChunk = fileInfo.getChunkNumber();
        Long allChunks = fileInfo.getTotalChunks();
        Long allSize = fileInfo.getTotalSize();
        if (currChunk < (allChunks)) {
            return chunkSize * (currChunk - 1);
        } else if (currChunk.equals(allChunks)) {
            return allSize - chunkSize;
        }
        throw new Exception("分片参数异常");
    }
}